import os
import sys
import shutil
import subprocess

from configure.compiler_names import CompilerName
from utils.common_utils import get_binary_path


class EnvConfig(object):
    
    IRGEN_GCC_ENV = ""
    IRGEN_CLANG_ENV = ""
    IRGEN_LD_ENV = ""
    IRGEN_AR_ENV = ""
    IRGEN_RANLIB_ENV = ""
    IRGEN_STRIP_ENV = ""
    IRGEN_PATH = ""
    IRGEN_PRELOAD = ""
    IRGEN_FILEIO_PRELOAD = ""
    IRGEN_WORK_PATH= ""
    IRGEN_CACHE_PATH= ""
    IRGEN_FILECACHE_SCRIPT = ""
    IRGEN_PATH_MIN_MATCH_PREFIX = "/root/progs"
    IRGEN_FilECHANGLE_SCRIPT = ""
    
    
    @staticmethod
    def update_runtime_env(env={}):
        env["IRGEN_PATH"] = EnvConfig.IRGEN_PATH
        env["IRGEN_WORK_PATH"] = EnvConfig.IRGEN_WORK_PATH
        env["IRGEN_PRELOAD"] = EnvConfig.IRGEN_PRELOAD
        env["IRGEN_GCC_SET"] = EnvConfig.IRGEN_GCC_ENV
        env["IRGEN_CLANG_SET"] = EnvConfig.IRGEN_CLANG_ENV
        env["IRGEN_LINK_SET"] = EnvConfig.IRGEN_LD_ENV
        env["IRGEN_ARCHIVE_SET"] = EnvConfig.IRGEN_AR_ENV
        env["IRGEN_RANLIB_SET"] = EnvConfig.IRGEN_RANLIB_ENV
        env["IRGEN_STRIP_SET"] = EnvConfig.IRGEN_STRIP_ENV
        env["IRGEN_OBJCOPY_SET"] = EnvConfig.IRGEN_OBJCOPY_ENV
        env["IRGEN_CCACHE_SET"] = EnvConfig.IRGEN_CCACHE_ENV
        env["IRGEN_CACHE_PATH"] = EnvConfig.IRGEN_CACHE_PATH
        env["IRGEN_FILEIO_PRELOAD"] = EnvConfig.IRGEN_FILEIO_PRELOAD
        env["IRGEN_FILECACHE_SCRIPT"] = EnvConfig.IRGEN_FILECACHE_SCRIPT
        env["IRGEN_PATH_MIN_MATCH_PREFIX"] = EnvConfig.IRGEN_PATH_MIN_MATCH_PREFIX
        env["IRGEN_FILECHANGE_SCRIPT"] = EnvConfig.IRGEN_FilECHANGLE_SCRIPT
    
    @staticmethod
    def set_environ(context=None):
        
        CompilerName.load_compiler_names(context.COMPILER_NAMES_FILE)
        
        EnvConfig.IRGEN_PATH = context.IRGEN_PATH
        EnvConfig.IRGEN_WORK_PATH = context.IRGEN_WORK_PATH
        EnvConfig.IRGEN_PRELOAD = context.CAPTURE_LIB
        EnvConfig.IRGEN_LD_LIB_PATH = context.LD_LIB_PATH
        EnvConfig.IRGEN_GCC_ENV = "?".join(CompilerName.gcc_names)
        EnvConfig.IRGEN_CLANG_ENV = "?".join(CompilerName.clang_names)
        EnvConfig.IRGEN_LD_ENV = '?'.join(CompilerName.ld_names)
        EnvConfig.IRGEN_AR_ENV = '?'.join(CompilerName.ar_names)
        EnvConfig.IRGEN_STRIP_ENV = '?'.join(CompilerName.strip_names)
        EnvConfig.IRGEN_RANLIB_ENV = '?'.join(CompilerName.ranlib_names)
        EnvConfig.IRGEN_OBJCOPY_ENV = '?'.join(CompilerName.objcopy_names)
        EnvConfig.IRGEN_CCACHE_ENV = '?'.join(CompilerName.ccache_names)
        EnvConfig.IRGEN_CACHE_PATH = context.CACHE_DIR
        EnvConfig.IRGEN_FILEIO_PRELOAD = context.CACHE_LIB
        

        python_path = get_binary_path("python")
        
        gcc_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/gcc_handler.py")
        clang_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/clang_handler.py")
        ld_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/ld_handler.py")
        ar_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/ar_handler.py")
        ranlib_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/ranlib_handler.py")
        strip_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/strip_handler.py")
        objcopy_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/objcopy_handler.py")
        ccache_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/ccache_handler.py")
        filecache_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/fcache_handler.py")
        filechange_handler_script = os.path.join(context.IRGEN_PATH, "tools_handler/fchange_handler.py")
        
        EnvConfig.IRGEN_GCC_ENV += ';' + python_path + ':' + gcc_handler_script
        EnvConfig.IRGEN_CLANG_ENV += ';' + python_path + ':' + clang_handler_script
        EnvConfig.IRGEN_LD_ENV += ';' + python_path + ':' + ld_handler_script
        EnvConfig.IRGEN_AR_ENV += ';' + python_path + ':' + ar_handler_script
        EnvConfig.IRGEN_RANLIB_ENV += ';' + python_path + ':' +  ranlib_handler_script
        EnvConfig.IRGEN_STRIP_ENV += ';' + python_path + ':' + strip_handler_script
        EnvConfig.IRGEN_OBJCOPY_ENV += ';' + python_path + ':' + objcopy_handler_script
        EnvConfig.IRGEN_CCACHE_ENV += ';' + python_path + ':' + ccache_handler_script
        EnvConfig.IRGEN_FILECACHE_SCRIPT = filecache_handler_script
        EnvConfig.IRGEN_FilECHANGLE_SCRIPT = filechange_handler_script
    
    
    @staticmethod    
    def check_compilers_version(context=None):
        EnvConfig.check_gcc_version(context=context)
        EnvConfig.check_clang_version(context=context)
        EnvConfig.check_ld_version(context=context)
        EnvConfig.check_ar_verison(context=context)
        EnvConfig.check_ranlib_version(context=context)
        EnvConfig.check_strip_version(context=context)
    
    @staticmethod
    def check_gcc_version(context=None, gcc_bin=""):
        if not gcc_bin:
            gcc_bin = shutil.which("gcc")
            
        if gcc_bin:
            command = [gcc_bin, "-dumpfullversion"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            gcc_ver = std_out.decode()
            context.GCC_VERSION = gcc_ver
        
        gcc_plus_bin = shutil.which("gcc")
        if  gcc_plus_bin:
            command = [gcc_plus_bin, "-dumpfullversion"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            gcc_plus_ver = std_out.decode()
            context.GCC_PLUS_VERSION = gcc_plus_ver
    
    @staticmethod
    def check_clang_version(context=None, clang_bin=""):
        if not clang_bin:
            clang_bin = shutil.which("clang")
        
        if clang_bin:
            command = [clang_bin, "-dumpversion"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            clang_ver = std_out.decode().rstrip()
            # context.CLANG_VERSION = clang_ver
            context.CLANG_VERSION = "6.0.0"
            # print(clang_ver)
        
        clangcpp_bin = shutil.which("clang++")
        if  clangcpp_bin:
            command = [clangcpp_bin, "-dumpversion"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            clangcpp_ver = std_out.decode().rstrip()
            context.CLANGCPP_VERSION = clangcpp_ver
            
    @staticmethod
    def check_ld_version(context=None, ld_bin=""):
        if not ld_bin:
            ld_bin = shutil.which("ld")
        if ld_bin:
            # now only verify in ubuntu
            command = [ld_bin, "--version"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            std_out = std_out.decode().splitlines()[0].rstrip()
            ld_ver = std_out.split(" ")[-1]
            context.LD_VERSION = ld_ver
            
    @staticmethod
    def check_ar_verison(context=None, ar_bin=""):
        if not ar_bin:
            ar_bin = shutil.which("ar")
        
        if ar_bin:
            command = [ar_bin, "--version"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            std_out = std_out.decode().splitlines()[0].rstrip()
            ar_ver = std_out.split(" ")[-1]
            context.AR_VERSION = ar_ver
    
    @staticmethod
    def check_ranlib_version(context=None, ranlib_bin=""):
        if not ranlib_bin:
            ranlib_bin = shutil.which("ranlib")
        
        if ranlib_bin:
            command = [ranlib_bin, "--version"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            std_out = std_out.decode().splitlines()[0].rstrip()
            ranlib_ver = std_out.split(" ")[-1]
            context.RANLIB_VERSION = ranlib_ver
    
    @staticmethod
    def check_strip_version(context=None, strip_bin=""):
        if not strip_bin:
            strip_bin = shutil.which("strip")
        
        if strip_bin:
            command = [strip_bin, "--version"]
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            std_out, _ = p.communicate()
            std_out = std_out.decode().splitlines()[0].rstrip()
            strip_ver = std_out.split(" ")[-1]
            context.STRIP_VERSION = strip_ver
    
    @staticmethod
    def active_capture_env(env={}):
        # only for linux
        if not env:
            return
        
        env["LD_PRELOAD"] = EnvConfig.IRGEN_PRELOAD
        if "LD_LIBRARY_PATH" in env:
            env["LD_LIBRARY_PATH"] = EnvConfig.IRGEN_LD_LIB_PATH + ":" +  env["LD_LIBRARY_PATH"]
        else:
            env["LD_LIBRARY_PATH"] = EnvConfig.IRGEN_LD_LIB_PATH
    
    @staticmethod
    def active_fcache_env(env={}):
        if not env:
            return 
        
        env["LD_PRELOAD"] = EnvConfig.IRGEN_FILEIO_PRELOAD
    
    @staticmethod
    def deactive_ldpre_env(env={}):
        if not env:
            return
        
        if "LD_PERLOAD" in env.keys():
            env.pop("LD_PRELOAD")